/**
 * This software was produced for the U. S. Government
 * under Contract No. FA8721-09-C-0002, and is
 * subject to the Rights in Noncommercial Computer Software
 * and Noncommercial Computer Software Documentation Clause
 * (DFARS) 252.227-7014 (JUN 1995)
 * 
 * (c) 2009 The MITRE Corporation. All Rights Reserved.
 *
 * SPMIF to OPNET Translator
 * Author: EWALTERS
 * Created: 11:10:31 PM, Nov 4, 2007
 * MITRE Corporation
 */
package com.mitre.spmif2opnet.analysis;

import java.util.Comparator;
import java.util.Hashtable;
import java.util.Map;
import java.util.TreeSet;
import java.util.Map.Entry;

import com.mitre.spmif2opnet.analysis.ast.Scenario;

/**
 * This priority calculator uses Rate Monotonic Analysis to calculate the priorities
 */
public class RMAPriorities extends Priorities {

	/**
	 * Interarrival times for each scenario task
	 */
	protected Map<String, Double> _spmif_periods;

	/**
	 * Default constructor
	 * @param type the type
	 */
	public RMAPriorities(PriorityType type) {
		super(type);
		_spmif_periods = new Hashtable<String, Double>();
	}
	
	/**
	 * Override - get the scenario period and add it
	 * @param proj_name project name
	 * @param scen scenario
	 */
	public void addSpmifPriority(String proj_name, Scenario scen) {
		Identifier id = new Identifier();
		id.setProjectName(proj_name);
		id.setScenarioName(scen.getName());
		_spmif_periods.put(id.toString(), scen.getInterarrivalTime());
	}

	/**
	 * In RMA, the rule is shortest period = highest priority
	 * Therefore, we sort by period, and then assign priorities accordingly! 
	 * This is the priority scheme we were talking about when we said that
	 *  we need global information.
	 */
	@Override
	public void calculate() throws AnalysisException {
		TreeSet<Entry<String, Double>> items = 
			new TreeSet<Entry<String, Double>>( new Comparator<Entry<String, Double>>() {
				public int compare(Entry<String, Double> arg0, 
						           Entry<String, Double> arg1) {
					if (arg0.getValue().doubleValue() == arg1.getValue().doubleValue()) { return 1; }
					else { return arg0.getValue().compareTo(arg1.getValue()); }
				}
			});
		for (Entry<String, Double> s_entry :_spmif_periods.entrySet()) {
			items.add(s_entry);
		}
		int p = new Double(this._opnet_scale).intValue() - 1;
		double prev_period = items.isEmpty() ? 0.0 : items.first().getValue();
		for (Entry<String, Double> entry : items) {
			if (entry.getValue() != prev_period) {
				--p;
				if (p < 0) {
					throw new AnalysisException("Too many priorities for RMAPriorities to track!  Re-do your Priorities!");
				}
			}
			prev_period = entry.getValue();
			this._opnet_priorities.put(entry.getKey(), p);
		}
		this._processed = true;
	}
	
	// NOTE: getOpnetPriority() is actually unchanged!

}
